#pragma once

#include <iostream>
#include <pthread.h>
#include <string>
#include <cstring>
#include <functional>
#include <cassert>
#include <unistd.h>

// class Thread;

// class Context // 上下文，将pthread_create中类内的第4个参数和this合并
// {
// public:
//     Context()
//         : _this(nullptr),
//           _args(nullptr)
//     {
//     }
//     ~Context()
//     {
//     }
//     Thread *_this; // 调用函数的this指针（线程当前的对象）
//     void *_args;   // 线程当前执行函数的参数
// };

// class Thread
// {
// public:
//     // using func_t = std::function<void*(void*)>;作用同下
//     typedef std::function<void *(void *)> func_t;
//     const int num = 1024;
//     //这样改就可以像C++一样，直接构造一个线程，然后传线程执行函数就行，不需要传线程函数参数和线程编号了！
//     //Thread(func_t func, void *args = nullptr, int number = 0)
//     Thread(func_t func, void *args, int number)
//         : _func(func),
//           _args(args)
//     {
//         // _name = "thread : ";
//         // _name += std::to_string(number);//和下面snprintf作用相同
//         char buffer[num];
//         snprintf(buffer, sizeof buffer, "thread : %d", number);
//         _name = buffer;

//         //void start()//可以直接把start函数拿进来
//         //{
//         Context *cnt = new Context();
//         cnt->_args = _args;
//         cnt->_this = this;
//         // 这里直接把cnt进行传参，直接把start_routine的参数和this指针都传过去了
//         int n = pthread_create(&_tid, nullptr, start_routine, cnt); // 这里_func会报错，C接口不能直接掉C++的函数对象
//         assert(0 == n);                                             // 线程创建成功函数返回值为0
//         (void)n;                                                    // 编译器在release版本会注释掉assert。会发现我们没有使用n，有的编译器就会报存在未使用变量n的警告，我们这里取消这个警告
//         //}
//     }

//     // 在类内创建线程，想让线程执行对应的方法，需要将方法设置为static(静态方法) —— 因为static类内函数没有this指针！

//     static void *start_routine(void *args) // 写一个函数，方便我们下面pthread_create第3个参数使用
//     {
//         // 很不幸，下面还是不能直接使用start_routine函数，因为start_routine是类内函数，有缺省参数！
//         // 也就是说start_routine有两个参数，第一个参数是Thread* this指针，第二个参数才是void* args
//         // return _func(args);

//         // 这里就又出问题了，静态函数只能调用静态方法和静态成员，不能调用类内成员方法和成员变量！
//         // 所以得换一种写法

//         Context *cnt = static_cast<Context *>(args);
//         void *ret = cnt->_this->run(cnt->_args); // 这里调用下面的run函数
//         delete cnt;
//         return ret;
//     }
//     // void start()//这里把start放外面，调用的时候要让线程调用start
//     // {
//     //     Context *cnt = new Context();
//     //     cnt->_args = _args;
//     //     cnt->_this = this;
//     //     // 这里直接把cnt进行传参，直接把start_routine的参数和this指针都传过去了
//     //     int n = pthread_create(&_tid, nullptr, start_routine, cnt); // 这里_func会报错，C接口不能直接掉C++的函数对象
//     //     assert(0 == n);                                             // 线程创建成功函数返回值为0
//     //     (void)n;                                                    // 编译器在release版本会注释掉assert。会发现我们没有使用n，有的编译器就会报存在未使用变量n的警告，我们这里取消这个警告
//     // }

//     void join()
//     {
//         int n = pthread_join(_tid, nullptr);
//         assert(n == 0);
//         (void)n;
//         //printf("%s\n", strerror(n));
//     }

//     void *run(void *args) // 给上面start_routine来用的
//     {
//         return _func(args);
//     }

//     ~Thread()
//     {
//     }

// private:
//     std::string _name; // 我们想直接看线程名字，比如线程1，线程2这种
//     pthread_t _tid;//线程的tid
//     func_t _func; // 线程未来执行的函数
//     void *_args;  // 线程执行函数的参数
// };

namespace my_thread
{
    typedef std::function<void *(void *)> func_t;
    const int num = 1024;
    class Thread
    {
        // 在类内创建线程，想让线程执行对应的方法，需要将方法设置为static(静态方法) —— 因为static类内函数没有this指针！
        static void *start_routine(void *args)
        {
            Thread *_this = static_cast<Thread *>(args);
            return _this->callback();
        }

    public:
        Thread()//构造不传参数
        {
            char namebuffer[num];
            snprintf(namebuffer, sizeof namebuffer, "thread : %d", threadnum++);
            _name = namebuffer;
        }
        void start(func_t func, void *args = nullptr)
        {
            _func = func;
            _args = args;
            int n = pthread_create(&_tid, nullptr, start_routine, this); // 这里直接传this指针
            assert(0 == n);
            (void)n;
        }
        // Thread(func_t func, void *args = nullptr) // 不要number了
        //     : _func(func),
        //       _args(args)
        // {
        //     char namebuffer[num];
        //     snprintf(namebuffer, sizeof namebuffer, "thread : %d", threadnum++);
        //     _name = namebuffer;
        // }
        // void start()
        // {
        //     int n = pthread_create(&_tid, nullptr, start_routine, this); // 这里直接传this指针
        //     assert(0 == n);
        //     (void)n;
        // }
        void join()
        {
            int n = pthread_join(_tid, nullptr);
            assert(n == 0);
            (void)n;
        }
        void *callback() // 不用传参数，回调函数自动调用类内成员变量 —— 下面的_args
        {
            return _func(_args); // 回调函数自动调用类内成员变量
        }
        std::string threadname() // 拿取线程名称
        {
            return _name;
        }
        ~Thread()
        {
        }

    private:
        std::string _name;    // 我们想直接看线程名字，比如线程1，线程2这种
        pthread_t _tid;       // 线程的tid
        func_t _func;         // 线程未来执行的函数
        void *_args;          // 线程执行函数的参数
        static int threadnum; // 这里为了避免麻烦就不加锁了
    };
    int Thread::threadnum = 1;
}
